# -*- coding: utf-8 -*-
# @Author: long
# @Date:   2018-06-02 23:36:40
# @Last Modified by:   ystlong
# @Last Modified time: 2018-06-03 19:55:02

import sqlite3

from filelist import PathList
from linuxfsconnect import LinuxFSPathConnect
import re
import os
import threading
import asyncthreading

scan_lock = threading.Lock()

class PathStorage(object):
	"""docstring for PathStorage"""
	def __init__(self):
		super(PathStorage, self).__init__()
	def condition(self, args):
		cond_arr = ["where 1=1"]
		limit_str = ''
		if args.has_key("page_offset") and args.has_key("page_per_page"):
			limit_str = "limit %s, %s"%(args["page_offset"], args["page_per_page"])
		for k in args:
			if k == "page_offset" or k == "page_per_page":
				continue
			cond_arr.append("and (1=1")
			for v in re.split("\s+", args[k]):
				# maybe need check sql 注入
				# 解析查询条件
				if v.startswith("\!"):
					# not equal
					cond_arr.append("and %s not like '%%%s%%'"%(k, v[2:]))
				elif v == "":
					pass
				else:
					cond_arr.append("and %s like '%%%s%%'"%(k, v))
			cond_arr.append(")")
		cond_arr.append(limit_str)
		return " ".join(cond_arr)

	def init(self):
		pass
	def get_all(self, **args):
		pass
	def get_by_id(self, **args):
		pass
	def get_total_count(self, **kargs):
		pass
	def query(self, **kargs):
		pass
	def insert(self, **kargs):
		pass
	def delete_all(self):
		pass
	def delete(self, **kargs):
		pass
	def update(self, **kargs):
		pass
	def close(self):
		pass
class SqlitePathStorage(PathStorage):
	"""docstring for SqlitePathStorage"""
	def __init__(self, db_name="test.db"):
		super(SqlitePathStorage, self).__init__()
		self.db_name = db_name
		self.get_conn(self.db_name)

	def get_conn(self, db_name):
		self.conn = sqlite3.connect(db_name)
		self.conn.row_factory = sqlite3.Row
		self.cur = self.conn.cursor()
		return self.conn

	def close(self):
		self.clean_scan_insert()
		self.conn.close()

	def init(self):
		create_sqls = [
			'''
			create table if not exists path_list(
			id integer primary key autoincrement,
			uri varchar(256),
			link varchar(512)
			);
			''',
			'''
			create table if not exists hosts_list(
			id integer primary key autoincrement,
			root_uri varchar(256),
			link_prefix varchar(512)
			);
		'''
		]
		for sql in create_sqls:
			self.cur.execute(sql)
			self.conn.commit()

	def get_total_count(self, **args):
		total_count_sql = "select count(*) from path_list %s"%(self.condition(args))
		rs = self.cur.execute(total_count_sql)
		return self.cur.fetchone()[0]

	def query(self, **args):
		sql = "select id, uri, link from path_list %s"%(self.condition(args))
		rs = self.cur.execute(sql)
		return self.cur.fetchall()

	def clean_scan_insert(self):
		insert_sql = '''
			insert into path_list(uri, link)
				select ?, ? 
				where not exists (select * from path_list where link=?)
		'''
		if hasattr(self, "scan_insert_datas") and len(self.scan_insert_datas) > 0:
			self.cur.executemany(insert_sql, self.scan_insert_datas)
			self.scan_insert_datas = []
			self.conn.commit()

	def insert(self, **args):
		insert_sql = '''
			insert into path_list(uri, link)
				select ?, ? 
				where not exists (select * from path_list where link=?)
		'''
		if not hasattr(self, "scan_insert_datas"):
			self.scan_insert_datas = []	
		self.scan_insert_datas.append((args['uri'], args['link'], args['link']))
		if len(self.scan_insert_datas) > 100:
			self.cur.executemany(insert_sql, self.scan_insert_datas)
			self.scan_insert_datas = []
			self.conn.commit()
		# sql = insert_sql.format(link=args["link"], uri=args["uri"])
		# self.cur.execute(insert_sql, [args['uri'], args['link'], args['link']])
		# self.conn.commit()

	def empty_all(self):
		sql = "delete from path_list where 1=1"
		self.cur.execute(sql)
		self.conn.commit()

	def empty(self, link_prefix):
		sql = "delete from path_list where link like '%s%%'"%(link_prefix)
		self.cur.execute(sql)
		self.conn.commit()

	def add_host(self, root_uri, link_prefix):
		insert_sql = '''
			insert into hosts_list(root_uri, link_prefix)
				select '{root_uri}', '{link_prefix}'
				where not exists (select * from hosts_list where root_uri='{root_uri}')
		'''
		sql = insert_sql.format(root_uri=root_uri, link_prefix=link_prefix)
		self.cur.execute(sql)
		self.conn.commit()

	def get_hosts(self):
		query_sql = "select id, root_uri, link_prefix from hosts_list" 
		self.cur.execute(query_sql)
		return self.cur.fetchall()

	def host_del(self, hostid):
		sql = "delete from hosts_list"
		if hostid != None:
			sql = "delete from hosts_list where id=%s"%(hostid)
		self.cur.execute(sql)
		self.conn.commit()

class PathFileIndex(object):
	"""docstring for PathFileIndex"""
	def __init__(self):
		super(PathFileIndex, self).__init__()
		self.storage = SqlitePathStorage()

	def handle_path_list(self, cur_abs_dir, cur_relate_dir, file_name, isdir=False, join_path=None):
		# if isdir:
		# 	print "d-",
		# else:
		# 	print "--",
		uri = join_path(cur_relate_dir, file_name)
		link = join_path(self.link_prefix, uri)
		self.storage.insert(uri=uri, link=link)

	def init(self):
		self.storage.init()

	def get_storage(self):
		return self.storage

	def write_scan_pid(self, pid):
		with open(".scan.tid", "w") as f:
			f.write("%ld"%(pid))

	def read_scan_tid(self):
		with open(".scan.tid") as f:
			tid = long(f.readline().strip())
			return tid

	def clean_scan_tid(self):
		if os.path.exists(".scan.tid"):
			os.system("rm .scan.tid")

	def gen_index(self, root_uris, link_prefixs, max_depth=5, backround=False):
		if len(root_uris) != len(link_prefixs):
			raise Exception("map path link not equal")
		def scans(thread=False):
			if scan_lock.locked():
				return
			scan_lock.acquire()
			self.write_scan_pid(threading.current_thread().ident)
			try:
				run_ctx = self
				if thread:
					run_ctx = PathFileIndex()
				print "start scan thread: ", threading.current_thread().getName()
				for i in xrange(len(root_uris)):
					path_conn = LinuxFSPathConnect()
					root_uri = path_conn.abs_uri(root_uris[i])
					run_ctx.link_prefix = link_prefixs[i]
					# now only local filesystem scan
					PathList().list_files(path_conn, run_ctx.handle_path_list, root_uri, "", max_depth)
				if thread:
					run_ctx.get_storage().close()
			except:
				raise
			finally:
				run_ctx.clean_scan_tid()
				scan_lock.release()
				print "finish scan thread: ", threading.current_thread().getName()

		if backround:
			t = threading.Thread(target=scans, args=(True,))
			t.setDaemon(True) #设置线程为后台线程
			t.start()
		else:
			scans()

	def stop_scan(self):
		tid = self.read_scan_tid()
		asyncthreading.stop_thread(tid)
		
	def list_dirs(self, root_uri):
		path_conn = LinuxFSPathConnect()
		return path_conn.list(root_uri)

	def abs_uri(self, uri):
		path_conn = LinuxFSPathConnect()
		return path_conn.abs_uri(uri)

	def join_path(self, p1, p2):
		path_conn = LinuxFSPathConnect()
		return path_conn.join_path(p1, p2)

	def parent_uri(self, uri):
		path_conn = LinuxFSPathConnect()
		return path_conn.parent_uri(uri)

def main():
	pfi = PathFileIndex()
	pfi.init()
	pfi.gen_index(["."], ["http://localhost"])
	rs = pfi.get_storage().query(uri="")
	print len(rs)
	print rs


if __name__ == '__main__':
	main()
